#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../utility.h"
#include "cli-command.h"
#include "../gpio/gwGpio.h"
#include "../hwicap/hwicap.h"

extern State xState;

unsigned int stringToDecimalInt(char* ret){
	if(ret == NULL){
		return -1;
	}
	int i;
	int len = strlen(ret);
	if(len < 1)
		return -1;
	unsigned int number = 0;
	int flag = 0;
	for(i=0;i<len;i++){
		if(ret[i] == '0' && flag == 0)
			continue;
		flag = 1;
		int temp = 0;
		if(ret[i]>='0'&&ret[i]<='9')
			temp = ret[i] - '0';
		if(i == len - 1)
			number = number + temp;
		else
			number = (number + temp)*10;
	}
	return number;
}

unsigned int stringToInt(char* ret){
	if(ret == NULL){
		return -1;
	}
	int i;
	int len = strlen(ret);
	if(len < 3)
		return -1;
	if(ret[0] != '0' || ret[1] != 'x')
		return -1;
	unsigned int number = 0;
	int flag = 0;
	for(i=2;i<len;i++){
		if(ret[i] == '0' && flag == 0)
			continue;
		flag = 1;
		int temp = 0;
		if(ret[i]>='0'&&ret[i]<='9')
			temp = ret[i] - '0';
		else if(ret[i]>='a'&&ret[i]<='f')
			temp = ret[i] - 'a' + 10;
		else if(ret[i]>='A'&&ret[i]<='F')
			temp = ret[i] - 'A' + 10;
		if(i == len - 1)
			number = number + temp;
		else
			number = (number + temp)*16;
	}
	return number;
}

int cli_spi_cmd(u32 data, u32 slave_mask, u8 *rx_data){
	int status = 0;
	if(data > 0x800000){
		status = cli_spi_read(data, slave_mask, rx_data);
	}else{
		status = cli_spi_write(data, slave_mask);
	}
	return status;
}

void cli_rapidio(char *pcWriteBuffer){

	if(xState.debug_fifo.debug_call_cnt == 0){
		return;
	}
	u8 start_idx = xState.debug_fifo.debug_read_idx;
	if(xState.debug_fifo.debug_call_cnt > RING_BUFFER_SIZE){
		start_idx = xState.debug_fifo.debug_buffer_idx;
	}

	int idx = 0;
	int j;
	// u8 *tmpPtr = xState.debug_fifo.debug_buffer_array[start_idx];
	u8 *tmpPtr = xState.debug_fifo.tmp_rx_ptr;
	if(tmpPtr != NULL){
		idx += sprintf( pcWriteBuffer+idx, " size  = %d ", xState.debug_fifo.debug_buffer_size[start_idx]);
		for(j=0;j<xState.debug_fifo.debug_buffer_size[xState.debug_fifo.debug_buffer_idx-1];j++){
			idx += sprintf( pcWriteBuffer+idx, " 0x%x ", tmpPtr[j]);
			// if(j % 8 == 0){
			// 	idx += sprintf( pcWriteBuffer+idx, "\r\n");
			// }
		}
		vPortFree(tmpPtr);
		xState.debug_fifo.debug_buffer_array[start_idx] = NULL;
	}
	xState.debug_fifo.debug_read_idx = xState.debug_fifo.debug_read_idx + 1;
	xState.debug_fifo.debug_read_idx = xState.debug_fifo.debug_read_idx & 0x3f; // 求余，ring循环
	xState.debug_fifo.debug_call_cnt = xState.debug_fifo.debug_call_cnt - 1;
}

// pcWriteBuffer 当前最大长度 1000
void cli_show(char *pcWriteBuffer){
	int idx = 0;
	u32 value = gw_ReadReg(FPGAVERSION_BASEADDRESS);
	char *fpga_version = parse_fpga_version(value);
	idx = sprintf( pcWriteBuffer, "Microblaze State : \r\n");
	idx += sprintf( pcWriteBuffer+idx, "    fpga_version : %s  \r\n", fpga_version);
	idx += sprintf( pcWriteBuffer+idx, "    microblaze_version : %s  \r\n", xState.version.strASCIICompileProfile);
	idx += sprintf( pcWriteBuffer+idx, "    Current free heap : %d bytes \r\n", ( int ) xPortGetFreeHeapSize());
	idx += sprintf( pcWriteBuffer+idx, "    minimum ever free heap : %d bytes\r\n", ( int ) xPortGetMinimumEverFreeHeapSize());
	idx += sprintf( pcWriteBuffer+idx, "    spi_configure ok : %d \r\n", xState.flag_spi_configure_ok);
	if(xState.cnt_spi_configure_failed != 0){
		idx += sprintf( pcWriteBuffer+idx, "    cnt_spi_configure_failed : %d \r\n", xState.cnt_spi_configure_failed);
	}
	if(xState.axi_address != 0x0){
		idx += sprintf( pcWriteBuffer+idx, "    axi_address : 0x%x \r\n", xState.axi_address);
	}
	idx += sprintf( pcWriteBuffer+idx, "    cnt_timer_call : %d \r\n", xState.cnt_timer_call);
	idx += sprintf( pcWriteBuffer+idx, "    agc_reset_num : %u \r\n", xState.agc_state.reset_num);
	idx += sprintf( pcWriteBuffer+idx, "    board_temper : %f \r\n", get_board_temper());
	idx += sprintf( pcWriteBuffer+idx, "    cnt_dma_tx : %d \r\n", xState.dma_state.tx_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    cnt_dma_rx : %d \r\n", xState.dma_state.rx_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    rx_error_cnt : %d \r\n", xState.dma_state.rx_error_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    tx_error_cnt : %d \r\n", xState.dma_state.tx_error_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    tx_test_cnt : %d \r\n", xState.dma_state.tx_test_cnt);

	idx += sprintf( pcWriteBuffer+idx, "    rx_error_ret : %d \r\n", xState.dma_state.rx_error_ret);
	idx += sprintf( pcWriteBuffer+idx, "    dma_rx_length : %d \r\n", xState.dma_state.rx_length);

	// idx += sprintf( pcWriteBuffer+idx, "    dma_tx_packet -- \r\n");
	// for(i=0;i<xState.dma_state.tx_length;i = i + 1){
	// 	idx += sprintf( pcWriteBuffer+idx, " 0x%x \r\n", xState.dma_state.test_TxPacket[i]);
	// }

	// idx += sprintf( pcWriteBuffer+idx, "    cnt_ext_uart_rx : %d \r\n", xState.ext_uart_state.rx_cnt);
	// idx += sprintf( pcWriteBuffer+idx, "    cnt_ext_uart_tx : %d \r\n", xState.ext_uart_state.tx_cnt);

	// idx += sprintf( pcWriteBuffer+idx, "    ext_uart_rx_length : %d \r\n", xState.ext_uart_state.rx_length);
	// idx += sprintf( pcWriteBuffer+idx, "    ext_uart_tx_length : %d \r\n", xState.ext_uart_state.tx_length);

	// idx += sprintf( pcWriteBuffer+idx, "    ext_uart_rx_buffer -- \r\n");
	// for(i=0;i<xState.ext_uart_state.rx_length;i = i + 1){
	// 	idx += sprintf( pcWriteBuffer+idx, " 0x%x \r\n", xState.ext_uart_state.test_extUartRxBuffer[i]);
	// }

	// idx += sprintf( pcWriteBuffer+idx, "    ext_uart_tx_buffer -- \r\n");
	// for(i=0;i<xState.ext_uart_state.tx_length;i = i + 1){
	// 	idx += sprintf( pcWriteBuffer+idx, " 0x%x \r\n", xState.ext_uart_state.test_extUartTxBuffer[i]);
	// }

	idx += sprintf( pcWriteBuffer+idx, "    rapid_io_1_cnt : %d \r\n", xState.dma_state.debug_cnt_state.rapid_io_1_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    rapid_io_2_cnt : %d \r\n", xState.dma_state.debug_cnt_state.rapid_io_2_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    rapid_io_3_cnt : %d \r\n", xState.dma_state.debug_cnt_state.rapid_io_3_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    rapid_io_4_cnt : %d \r\n", xState.dma_state.debug_cnt_state.rapid_io_4_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    rapid_io_5_cnt : %d \r\n", xState.dma_state.debug_cnt_state.rapid_io_5_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    doorbell_cnt : %d \r\n", xState.dma_state.debug_cnt_state.doorbell_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    send_en_1_cnt : %d \r\n", xState.dma_state.debug_cnt_state.send_en_1_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    send_en_2_cnt : %d \r\n", xState.dma_state.debug_cnt_state.send_en_2_cnt);
	idx += sprintf( pcWriteBuffer+idx, "    send_en_doorbell_cnt : %d \r\n", xState.dma_state.debug_cnt_state.send_en_doorbell_cnt);

	idx += sprintf( pcWriteBuffer+idx, "    idx =  %d\r\n", idx);

	vPortFree(fpga_version);
}

void cli_control_mode(u32 mode){
	switch (mode)
	{
		case 0:
			gpio_loopback();
			break;

		case 1:
			gpio_normal();
			break;

		case 2:
			gpio_rx_out();
			break;

		case 3:
			gpio_tx_out();
			break;	
		default:
			break;
	}
}

void set_gpio_value(u32 value, u32 address){
	if(value == 0x0){
		reset_gpio(address);
	}else if(value == 0x1){
		set_gpio(address);
	}
}


/* dma interface */
int cli_dma_send(u8* tx_data){
	int len = strlen(tx_data) + 1;
	int Status = dma_tx(tx_data, len);
	return Status;
}

int cli_dma_send_continue(u32 test_cnt, u32 clear_cnt){
	enable_tx_test(test_cnt, clear_cnt);
	return 0;
}

/* switch fpga bitfile interface */
int cli_switch_fpga(u8 num){
	int ret = XST_SUCCESS;
	if(num == 1){
		ret = HwIcapLoadBit(BIT_1_FLASH_IMAGE_BASEADDR);
	}else if(num == 2){
		ret = HwIcapLoadBit(BIT_2_FLASH_IMAGE_BASEADDR);
	}
	return ret;
}
